package com.qisimanxiang.dalaran.zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import com.qisimanxiang.dalaran.zuul.param.PublicParam;
import com.qisimanxiang.dalaran.zuul.util.JsonMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

import static com.qisimanxiang.dalaran.zuul.util.ContextConstant.PUBLIC_PARAM_KEY;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

@Component
@Slf4j
public class CustomPreFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return Integer.MAX_VALUE;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        try {
            RequestContext currentContext = RequestContext.getCurrentContext();
            String contextURI = (String) currentContext.get(FilterConstants.REQUEST_URI_KEY);
            String serviceId = (String) currentContext.get(FilterConstants.SERVICE_ID_KEY);
            HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
            String body = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
            PublicParam publicParam = JsonMapper.NON_NULL.prase(StringUtils.isEmpty(body) ? "{}" : body, PublicParam.class);
            currentContext.set(PUBLIC_PARAM_KEY, publicParam);
            if (log.isDebugEnabled()) {
                log.info("请求服务:{}", serviceId);
                log.info("请求路径:{}", contextURI);
                log.info("请求body:{}", body);
                log.info("公共参数:{}", publicParam);
            }
            currentContext.setRequest(buildWrapper(request, body));
        } catch (IOException e) {
            log.error("网关异常", e);
            throw new RuntimeException("网关异常", e);
        }
        return null;
    }


    public HttpServletRequest buildWrapper(HttpServletRequest request, String body) {

        byte[] bytes = body == null ? new byte[0] : body.getBytes(StandardCharsets.UTF_8);
        return new HttpServletRequestWrapper(request) {
            @Override
            public ServletInputStream getInputStream() {
                return new ServletInputStreamWrapper(bytes);
            }

            @Override
            public int getContentLength() {
                return bytes.length;
            }

            @Override
            public long getContentLengthLong() {
                return bytes.length;
            }
        };
    }

}
